/*
 * Copyright (c) 2010-2011, okazoh_tk. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 *  - Redistributions of source code must retain the above copyright notice,
 *    this list of conditions and the following disclaimer.
 *  - Redistributions in binary form must reproduce the above copyright notice,
 *    this list of conditions and the following disclaimer in the documentation
 *    and/or other materials provided with the distribution.
 *  - Neither the name of the copyright holder nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

#include "./GLPrivate.h"

#include "alkes/opengl/GLState.h"
#include "alkes/opengl/GLWrapper.h"

namespace alkes {

#if defined(ALKES_GLES2)
#define DISABLE_CLIENT_STATE
#define DISABLE_MULTISAMPLE
#endif

#ifndef TRACE_GL_STATE
#define TRACE_GL_STATE 0
#endif

#define TRACE_GL_STATE_LOG(exp, state)  LOGV_IF(TRACE_GL_STATE, exp, state)

#undef AL_OGL_ST
#define AL_OGL_ST(name) GL_##name
#define _DEFINE_TABLE

const static GLenum s_server_states[] = {
#include "alkes/opengl/ServerState.inl"
};

GLState::GLState()
{
    // initial state is true.
    server_states_.setFlag(AL_OGL_ST_DITHER);
    server_states_.setFlag(AL_OGL_ST_MULTISAMPLE);
}

GLState::~GLState()
{
}

bool GLState::isEnable(ServerState state) const
{
    return server_states_[state];
}

void GLState::set(ServerState state, bool is_enable)
{
    if (is_enable)
        enable(state);
    else
        disable(state);
}

void GLState::enable(ServerState state)
{
    if (state < 0 || AL_LENGTH(s_server_states) <= state)
        return ;

    if (!server_states_[state])
    {
        server_states_.setFlag(state);
        AL_OGL_INVOKE(glEnable(s_server_states[state]));
        TRACE_GL_STATE_LOG("glEnable(%d)", state);
    }
}

void GLState::disable(ServerState state)
{
    if (state < 0 || AL_LENGTH(s_server_states) <= state)
        return ;

    if (server_states_[state])
    {
        server_states_.clearFlag(state);
        AL_OGL_INVOKE(glDisable(s_server_states[state]));
        TRACE_GL_STATE_LOG("glDisable(%d)", state);
    }
}

#if !defined(DISABLE_CLIENT_STATE)

const static GLenum s_client_states[] = {
#include "alkes/opengl/ClientState.inl"
};

bool GLState::isEnable(ClientState state) const
{
    return client_states_[state];
}

void GLState::set(ClientState state, bool is_enable)
{
    if (is_enable)
        enable(state);
    else
        disable(state);
}

void GLState::enable(ClientState state)
{
    if (state < 0 || AL_LENGTH(s_client_states) <= state)
        return ;

    if (!client_states_[state])
    {
        client_states_.setFlag(state);
        AL_OGL_INVOKE(glEnableClientState(s_client_states[state]));
        TRACE_GL_STATE_LOG("glEnableClientState(%d)", state);
    }
}

void GLState::disable(ClientState state)
{
    if (state < 0 || AL_LENGTH(s_client_states) <= state)
        return ;

    if (client_states_[state])
    {
        client_states_.clearFlag(state);
        AL_OGL_INVOKE(glDisableClientState(s_client_states[state]));
        TRACE_GL_STATE_LOG("glDisableClientState(%d)", state);
    }
}

#else

bool GLState::isEnable(ClientState /*state*/) const
{
    return false;
}

void GLState::set(ClientState /*state*/, bool /*is_enable*/)
{
}

void GLState::enable(ClientState /*state*/)
{
}

void GLState::disable(ClientState /*state*/)
{
}

#endif

}
